package org.japo.java.jdbc.samples;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author José A. Pacheco Ondoño - joanpaon@gmail.com
 */
public class AccesoModulos {

    // Nombre de la base de datos
    private final String BD = "Agenda";

    // SGBD soportador - Selección del SGBD activo
    private final String PRODUCTO1 = "Access";   // Access
    private final String PRODUCTO2 = "MySQL";    // MySQL
    private final String PRODUCTO_ACTIVO = PRODUCTO2;

    // Referencias para la gestión de la base de datos
    private Connection con = null;
    private Statement stmt = null;

    public static void main(String[] args) {
        try {
            // Crea una instancia de la propia clase
            AccesoModulos aplicacion = new AccesoModulos();

            // Ejecuta el aplicativo
            aplicacion.lanzarAplicacion();
        } catch (Exception e) {
            Logger.getLogger(AccesoModulos.class.getName()).log(Level.SEVERE, null, e);
        }
    }

    private void lanzarAplicacion() throws Exception {
        try {
            // Crear el acceso a la base de datos
            crearAccesoDatos(BD);

            // Procesa los datos
            procesarDatos();
        } finally {
            // Cerrar la base de datos
            cerrarBD();
        }
    }

    private void crearAccesoDatos(String bd) {
        try {
            // Establecer conexión con la base de datos
            con = conectarBD(bd);

            // ---- CAMBIOS DE DATOS ----
            // ResultSet.TYPE_FORWARD_ONLY (*) - Indica que el objeto ResultSet se 
            //      puede recorrer unicamente hacia adelante.
            // ResultSet.TYPE_SCROLL_INSENSITIVE - Indica que el objeto ResultSet se 
            //      puede recorrer, pero en general no es sensible a los cambios en 
            //      los datos que subyacen en él.
            // ResultSet.TYPE_SCROLL_SENSITIVE - Indica que el objeto ResultSet se 
            //      puede recorrer, y además, los cambios en él repercuten
            //      en la base de datos subyacente.
            // ---- MODOS DE CONCURRENCIA ----
            // ResultSet.CONCUR_READ_ONLY (*) - Indica que en el modo de concurrencia 
            //      para el objeto ResultSet éste no puede ser actualizado.
            // ResultSet.CONCUR_UPDATABLE - Indica que en el modo de concurrencia 
            //      para el objeto ResultSet éste podria ser actualizado.
            //
            // Crear una sentencia
            stmt = con.createStatement();
        } catch (Exception e) {
            // Información de depuración
            Logger.getLogger(AccesoModulos.class.getName()).log(Level.SEVERE, null, e);

            // Cierra la base de datos
            cerrarBD();

            // Finaliza el programa
            terminarPrograma();
        }
    }

    private Connection conectarBD(String bd) throws Exception {
        // Referencia a la conexión
        Connection c;

        // Conecta con la base de datos
        if (PRODUCTO_ACTIVO.equals(PRODUCTO1)) {
            c = conectarAccess(bd);
        } else if (PRODUCTO_ACTIVO.equals(PRODUCTO2)) {
            c = conectarMySQL(bd);
        } else {
            throw new Exception("No se ha seleccionado producto");
        }

        // Devuelve la conexión obtenida
        return c;
    }

    private Connection conectarAccess(String bd) throws Exception {
        // Conexión
        Connection c;

        // Protocolo del driver
        final String PROTOCOLO_ACCESS = "jdbc:odbc";

        // Cadena de conexión de Access
        final String CADENA_ACCESS = PROTOCOLO_ACCESS + ":" + bd;

        // Realiza la conexión
        System.out.println("Abriendo " + bd + " ...");
        c = DriverManager.getConnection(CADENA_ACCESS);
        System.out.println("Base de datos " + bd + " conectada.");

        // Devolver la conexión obtenida
        return c;
    }

    private Connection conectarMySQL(String bd) throws Exception {
        // Conexión
        Connection c;

        // Protocolo del driver
        final String PROTOCOLO_MySQL = "jdbc:mysql";

        // Servidor
        final String SERVIDOR = "localhost";
        final int PUERTO = 3306;

        // Usuario
        final String USUARIO = "usuario";
        final String PASSWORD = "usuario";

        // Cadena de conexión de MySQL
        final String CADENA_MySQL = ""
                + PROTOCOLO_MySQL + "://"
                + SERVIDOR + ":"
                + PUERTO + "/"
                + bd;

        // Realiza la conexión
        System.out.println("Abriendo " + bd + " ...");
        c = DriverManager.getConnection(CADENA_MySQL, USUARIO, PASSWORD);
        System.out.println("Base de datos " + bd + " conectada.");

        // Devolver la conexión obtenida
        return c;
    }

    private void procesarDatos() throws Exception {
        // Lista los datos
        mostrarDatos();
    }

    private void mostrarDatos() throws Exception {
        // Preparación del acceso
        final String SQL = "SELECT * FROM Modulo";

        // Lista los datos
        try (ResultSet rs = stmt.executeQuery(SQL)) {
            // Lista los datos
            listarDatos(rs);
        }
    }

    private void listarDatos(ResultSet rs) throws SQLException {
        // Variables para los campos
        int id;
        String acronimo;
        String nombre;
        String codigo;
        int horas;
        int curso;
        String linea;

        // Recorrido del Resultset
        while (rs.next()) {
            // Las columnas del ResultSet enpiezan en 1
            // Se pueden referir por su nombre o su posición
            id = rs.getInt(1);
            acronimo = rs.getString(2);
            nombre = rs.getString(3);
            codigo = rs.getString(4);
            horas = rs.getInt(5);
            curso = rs.getInt(6);

            // Genera una linea de texto con los datos
            linea = String.format("%03d - %-3d - %6s - %-50s - %-7s - %3d - %d",
                    rs.getRow(), id, codigo, nombre, acronimo, horas, curso);

            // Muestra la linea
            System.out.println(linea);
        }
    }

    private void cerrarBD() {
        // Mensaje
        System.out.println("Cerrando " + BD + " ...");

        // Cierra el Statement
        try {
            stmt.close();
        } catch (SQLException | NullPointerException e) {
            Logger.getLogger(AccesoModulos.class.getName()).log(Level.SEVERE, null, e);
        }

        // Cierra la conexión
        try {
            con.close();
        } catch (SQLException | NullPointerException e) {
            Logger.getLogger(AccesoModulos.class.getName()).log(Level.SEVERE, null, e);
        }

        // Mensaje
        System.out.println("Base de datos " + BD + " cerrada.");
    }

    private void terminarPrograma() {
        System.exit(0);
    }
}
